﻿using BaseMsg;
using System;
using System.IO;

public class LuaMsg
{
    const int MAX_MSG_HEAD_LEN = 10 * GlobalNum.MAX_GUIDEID;
    const int MAX_MSG_BODY_LEN = 10 * GlobalNum.FILE_SIZE;

    public delegate byte[] SerializeFunc(LuaMsg msg);
    public delegate bool DeserializeFunc(LuaMsg msg, MemoryStream ms);
    
    public static SerializeFunc SerializeHeadFunc;
    public static DeserializeFunc DeserializeHeadFunc;

    public int id;
    public MsgHead head;
    public byte[] body;

    public static void Init(SerializeFunc vSerializeHeadFunc, DeserializeFunc vDeserializeHeadFunc)
    {
        SerializeHeadFunc = vSerializeHeadFunc;
        DeserializeHeadFunc = vDeserializeHeadFunc;
    }

    public static LuaMsg DeserializeMsg(byte[] ss, int startIdx, int len)
    {
        //消息格式
        //msg总长度|MessageHead长度|MessageHead|MessageBody长度|MessageBody|8字节对齐内容|
        LuaMsg msg = new LuaMsg();
        
        //1.解析出消息头长度
        var index = startIdx;
        int msgHeadLen = BitConverter.ToInt16(ss, index);
        if (msgHeadLen < 0 || msgHeadLen > MAX_MSG_HEAD_LEN)
        {
            Console.WriteLine("Msg head len < 0 or > {0}", MAX_MSG_HEAD_LEN);
            return null;
        }
        index += 2;

        //2.解析出消息头内容
        var bMsgHead = new byte[msgHeadLen];
        Array.Copy(ss, index, bMsgHead, 0, msgHeadLen);
        var msMsgHead = new MemoryStream(bMsgHead);
        if (!DeserializeHeadFunc(msg, msMsgHead))
        {
            return null;
        }
        index += msgHeadLen;
        
        //3.解析出消息体长度
        int msgBodyLen = BitConverter.ToInt32(ss, index);
        if (msgBodyLen < 0 || msgBodyLen > MAX_MSG_BODY_LEN)
        {
            Console.WriteLine("Msg body len < 0 or > {0}", MAX_MSG_BODY_LEN);
            return null;
        }
        index += 4;
        
        //4.解析出消息体内容
        var bMsgBody = new byte[msgBodyLen];
        Array.Copy(ss, index, bMsgBody, 0, msgBodyLen);
        msg.body = bMsgBody;
        return msg;
    }


    public static byte[] SerializeMsg(LuaMsg msg)
    {
        //消息格式
        //msg总长度|MessageHead长度|MessageHead|MessageBody长度|MessageBody|8字节对齐内容|
        
        //序列化 head
        byte[] msgHeadBytes = SerializeHeadFunc(msg);
        if (msgHeadBytes == null)
        {
            return null;
        }
        int msgHeadLen = msgHeadBytes.Length;
        if (msgHeadLen < 0 || msgHeadLen > MAX_MSG_HEAD_LEN)
        {
            Console.WriteLine("Msg head len < 0 or > {0}", MAX_MSG_HEAD_LEN);
            return null;
        }

        //序列化 body
        byte[] msgBodyBytes = msg.body;
        if (msgBodyBytes == null)
        {
            return null;
        }
        int msgBodyLen = msgBodyBytes.Length;
        if (msgBodyLen < 0 || msgBodyLen > MAX_MSG_BODY_LEN)
        {
            Console.WriteLine("Msg body len < 0 or > {0}", MAX_MSG_BODY_LEN);
            return null;
        }
        
        //总长度
        int totolNum = 4 + 2 + msgHeadBytes.Length + 4 + msgBodyBytes.Length;
        
        //计算需要补齐的字节数
        int paddingNum = totolNum % 8;
        if (paddingNum != 0)
        {
            paddingNum = 8 - paddingNum;
        }
        //补齐数据
        var paddingBytes = new byte[paddingNum];
        totolNum += paddingNum;
        
        var ms = new MemoryStream();
        //写入总长度
        ms.Write(ConvertIntToByte(totolNum), 0, 4);
        //写入消息头长度
        ms.Write(ConvertIntToByte(msgHeadBytes.Length), 0, 2);
        //写入消息头
        ms.Write(msgHeadBytes, 0, msgHeadBytes.Length);
        //写入消息体长度
        ms.Write(ConvertIntToByte(msgBodyBytes.Length), 0, 4);
        //写入消息体
        ms.Write(msgBodyBytes, 0, msgBodyBytes.Length);
        if (paddingNum > 0)
        {
            //写入补齐数据
            ms.Write(paddingBytes, 0, paddingBytes.Length);
        }
        byte[] data = ms.ToArray();
        return data;
    }

    private static byte[] ConvertIntToByte(int d)
    {
        var re = BitConverter.GetBytes(d);
        //Array.Reverse(re); 
        return re;
    }

    private static byte[] ConvertLongToByte(long d)
    {
        var re = BitConverter.GetBytes(d);
        //Array.Reverse(re); 
        return re;
    }
}